rtt-target 0.3.1

Target side implementation of the RTT (Real-Time Transfer) I/O protocol
Documentation

Target side implementation of the RTT (Real-Time Transfer) I/O protocol

RTT implements input and output to/from a debug probe using in-memory ring buffers and memory polling. This enables debug logging from the microcontroller with minimal delays and no blocking, making it usable even in real-time applications where e.g. semihosting delays cannot be tolerated.

Hardware support

This crate is platform agnostic and can be used on any chip that supports background memory access via its debug interface. The printing macros require a critical section which is platform-dependent. Built-in ARM Cortex-M support can be enabled with the "cortex-m" feature, and RISC-V support can be enabled with the "riscv" feature.

To interface with RTT from the host computer, a debug probe such as an ST-Link or J-Link is required. The normal debug protocol (e.g. SWD) is used to access RTT, so no extra connections such as SWO pins are needed.

Initialization

RTT must be initialized at the start of your program using one of the init macros. See the macros for more details.

The initialization macros return channel objects that can be used for writing and reading. Different channel objects can safely be used concurrently in different contexts without locking. In an interrupt-based application with realtime constraints you could use a separate channel for every interrupt context to allow for lock-free logging.

Channels and virtual terminals

RTT supports multiple channels in both directions. Up channels go from target to host, and down channels go from host to target. Each channel is identified by its direction and number.

By convention channel 0 is reserved for terminal use. In the up direction there is a set of escape sequences that further enable the single channel to be treated as up to 16 virtual terminals. This can be used to separate different types of messages (for example, log levels) from each other without having to allocate memory for multiple buffers. As a downside, multiple threads cannot write to the same channel at once, even if using different virtual terminal numbers, so access has to be synchronized. Down channel 0 is conventionally used for keyboard input.

Note: Some host side programs only display channel 0 by default, so to see the other channels you might need to configure them appropriately.

The other channels can be used to either enable concurrent use from multiple sources without locking, or to send e.g. binary data in either direction.

Channel 0 can also be used for arbitrary data, but most tools expect it to be plain text.

Channel modes

By default, channels start in NoBlockSkip mode, which discards data if the buffer is full. This enables RTT to not crash the application if there is no debug probe attached or if the host is not reading the buffers. However if the application outputs faster than the host can read (which is easy to do, because writing is very fast), messages will be lost. Channels can be set to blocking mode if this is desirable, however in that case the application will likely freeze when the buffer fills up if a debugger is not attached.

The channel mode can also be changed on the fly by the debug probe. Therefore it may be advantageous to use a non-blocking mode in your microcontroller code, and set a blocking mode as needed when debugging. That way you will never end up with an application that freezes without a debugger connected.

Printing

For no-hassle output the [rprint] and [rprintln] macros are provided. They use a single down channel defined at initialization time, and a critical section for synchronization, and they therefore work exactly like the standard println style macros. They can be used from any context. The [rtt_init_print] convenience macro initializes printing on channel 0.

use rtt_target::{rtt_init_print, rprintln};

fn main() -> ! {
rtt_init_print!();
loop {
rprintln!("Hello, world!");
}
}

The macros also support an extended syntax to print to different RTT virtual terminals.

Please note that because a critical section is used, printing into a blocking channel will cause the application to block and freeze when the buffer is full.